package com.amose.factory;

import com.amose.config.Configuration;
import com.amose.config.MapperStatement;

import java.lang.reflect.*;
import java.util.Collection;
import java.util.List;

/**
 * @author yangpeng
 * @time 2020/2/22
 * @since 1.0.0
 */
public class DefaultSqlSession implements SqlSession{

    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration){
        this.configuration = configuration;
    }

    @Override
    public <T> List<T> queryList(String statementId, Object... params) throws Exception {
        MapperStatement mapperStatement = configuration.getSqlMapperStatement().get(statementId);
        return new SimpleExecutor().queryList(configuration, mapperStatement, params);
    }

    @Override
    public <T> T queryOne(String statementId, Object... params) throws Exception {
        MapperStatement mapperStatement = configuration.getSqlMapperStatement().get(statementId);
        return new SimpleExecutor().queryOne(configuration, mapperStatement, params);
    }

    @Override
    public int update(String statementId, Object... params) throws Exception {
        MapperStatement mapperStatement = configuration.getSqlMapperStatement().get(statementId);
        return new SimpleExecutor().update(configuration, mapperStatement, params);
    }

    @Override
    public <E> E getProxyMapper(Class<?> eClass) {
        Object proxy = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{eClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();
                String statementId = className + "." + methodName;
                MapperStatement mapperStatement = configuration.getSqlMapperStatement().get(statementId);
                Class<?> returnType = method.getReturnType();
                String sqlType = mapperStatement.getSqlType();
                switch (sqlType) {
                    case "select":
                        if (returnType.isAssignableFrom(List.class)) {
                            List<Object> objects = queryList(statementId, args);
                            return objects;
                        }
                        return queryOne(statementId, args);
                    case "insert":
                        return update(statementId,args);
                    case "update":
                        return update(statementId,args);
                    case "delete":
                        return update(statementId,args);
                    default:
                        break;
                }
                return null;
            }
        });
        return (E) proxy;
    }
}
